<template>
  <ThreeBox ref="container"></ThreeBox>
</template>

<script setup>
import ThreeBox from "../../components/ThreeBox.vue";
import { ref, onMounted } from "vue";
import axios from "axios";
import * as THREE from "three";
import { TWEEN } from "../../lib/three/libs/tween.module.min";
import { vec4 } from "gl-matrix";
import { getModelViewMatrix } from "../../lib/math/GetMatrix";

const container = ref(null);
let threeBox = null;
let threePara = null;
let scene = new THREE.Scene();
let material = null;
let pointsInit = new THREE.Object3D();
let pointsVertices = null;
let oldTime = Date.now();
let nowModel = 1;
let loadReady = false;
let pointsOne = null;
let pointsTwo = null;
let pointsThree = null;
let pointsFour = null;
let pointsFive = null;

function animate() {
  requestAnimationFrame(animate);
  TWEEN.update();
  render();
}

function render() {
  //屏幕刷新时间
  let newTime = Date.now();
  let delta = newTime - oldTime;
  oldTime = newTime;

  if (!loadReady) {
    pointsInit.rotation.y -= -(delta * 0.0005);
  } else {
    pointsInit.rotation.y = 0;
  }

  threePara.renderer.render(scene, threePara.camera);
}

function getMaterial() {
  let canvas = document.createElement("canvas");
  canvas.width = 16;
  canvas.height = 16;

  let ctx = canvas.getContext("2d");
  let grd = ctx.createRadialGradient(
    canvas.width / 2,
    canvas.height / 2,
    0,
    canvas.width / 2,
    canvas.height / 2,
    canvas.width / 2
  );

  grd.addColorStop(0, "rgba(255,255,255,1)");
  grd.addColorStop(0.2, "rgba(0,255,255,1)");
  grd.addColorStop(0.4, "rgba(0,0,64,1)");
  grd.addColorStop(1, "rgba(0,0,0,1)");

  ctx.fillStyle = grd;
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  let texture = new THREE.Texture(canvas);
  texture.needsUpdate = true;

  return texture;
}

function getModels() {
  //获取模型一
  axios({
    method: "get",
    url: "./three/models/cpgame3.json",
  }).then((res) => {
    let points = new Float32Array(res.data.vertices);

    let position = { x: -0.8, y: 0.2, z: -1 };
    let rotation = { x: 0.35 * Math.PI, y: 0.15 * Math.PI, z: -0.1 * Math.PI };
    let scale = { x: 1, y: 1, z: 1 };
    let modelViewMatrix = getModelViewMatrix(position, rotation, scale);

    for (let i = 0; i < points.length; i += 3) {
      let point = vec4.fromValues(points[i], points[i + 1], points[i + 2], 1);
      let out = new Float32Array(4);
      vec4.transformMat4(out, point, modelViewMatrix);
      points[i] = out[0];
      points[i + 1] = out[1];
      points[i + 2] = out[2];
    }
    pointsOne = points;
  });

  //获取模型二
  axios({
    method: "get",
    url: "./three/models/cpac5.json",
  }).then((res) => {
    let points = new Float32Array(res.data.vertices);

    let position = { x: 1.2, y: -0.1, z: -1 };
    let rotation = { x: 0, y: -0.15 * Math.PI, z: 0 };
    let scale = { x: 1, y: 1, z: 1 };
    let modelViewMatrix = getModelViewMatrix(position, rotation, scale);

    for (let i = 0; i < points.length; i += 3) {
      let point = vec4.fromValues(points[i], points[i + 1], points[i + 2], 1);
      let out = new Float32Array(4);
      vec4.transformMat4(out, point, modelViewMatrix);
      points[i] = out[0];
      points[i + 1] = out[1];
      points[i + 2] = out[2];
    }
    pointsTwo = points;
  });

  //获取模型三
  axios({
    method: "get",
    url: "./three/models/cpbook2.json",
  }).then((res) => {
    let points = new Float32Array(res.data.vertices);

    let position = { x: 1.3, y: 0.3, z: -1 };
    let rotation = { x: 0.1 * Math.PI, y: 0.1 * Math.PI, z: 0 };
    let scale = { x: 1, y: 1, z: 1 };
    let modelViewMatrix = getModelViewMatrix(position, rotation, scale);

    for (let i = 0; i < points.length; i += 3) {
      let point = vec4.fromValues(points[i], points[i + 1], points[i + 2], 1);
      let out = new Float32Array(4);
      vec4.transformMat4(out, point, modelViewMatrix);
      points[i] = out[0];
      points[i + 1] = out[1];
      points[i + 2] = out[2];
    }
    pointsThree = points;
  });

  //获取模型四
  axios({
    method: "get",
    url: "./three/models/cpmovie4.json",
  }).then((res) => {
    let points = new Float32Array(res.data.vertices);

    let position = { x: -1.8, y: 0, z: -4 };
    let rotation = { x: 0.5 * Math.PI, y: 0 * Math.PI, z: 1.2 * Math.PI };
    let scale = { x: 1, y: 1, z: 1 };
    let modelViewMatrix = getModelViewMatrix(position, rotation, scale);

    for (let i = 0; i < points.length; i += 3) {
      let point = vec4.fromValues(points[i], points[i + 1], points[i + 2], 1);
      let out = new Float32Array(4);
      vec4.transformMat4(out, point, modelViewMatrix);
      points[i] = out[0];
      points[i + 1] = out[1];
      points[i + 2] = out[2];
    }
    pointsFour = points;
  });

  //获取模型五
  axios({
    method: "get",
    url: "./three/models/cpkv3.json",
  }).then((res) => {
    let points = new Float32Array(res.data.vertices);

    let position = { x: 0, y: -0.5, z: -5 };
    let rotation = { x: 0.1 * Math.PI, y: 0, z: 0 };
    let scale = { x: 0.3, y: 0.3, z: 0.3 };
    let modelViewMatrix = getModelViewMatrix(position, rotation, scale);

    for (let i = 0; i < points.length; i += 3) {
      let point = vec4.fromValues(points[i], points[i + 1], points[i + 2], 1);
      let out = new Float32Array(4);
      vec4.transformMat4(out, point, modelViewMatrix);
      points[i] = out[0];
      points[i + 1] = out[1];
      points[i + 2] = out[2];
    }
    pointsFive = points;
  });
}

function transformModel(num) {
  let points = null;

  switch (num) {
    case 1:
      points = pointsOne;
      break;
    case 2:
      points = pointsTwo;
      break;
    case 3:
      points = pointsThree;
      break;
    case 4:
      points = pointsFour;
      break;
    case 5:
      points = pointsFive;
      break;
  }

  new TWEEN.Tween({ val: 0 })
    .to({ val: 1 }, 5000)
    .easing(TWEEN.Easing.Exponential.InOut)
    .onUpdate(function () {
      let val = this._object.val;
      for (var i = 0; i < pointsVertices.length; i++) {
        pointsVertices[i] +=
          (points[i % points.length] - pointsVertices[i]) * val;
      }
      pointsInit.geometry.setAttribute(
        "position",
        new THREE.Float32BufferAttribute(pointsVertices, 3)
      );
    })
    .onComplete(function () {
      if (nowModel < 5) transformModel(++nowModel);
    })
    .start();
}

function init() {
  //创建纹理
  material = new THREE.PointsMaterial({
    map: getMaterial(),
    size: 0.05,
    color: 0xffffff,
    blending: THREE.AdditiveBlending,
    depthTest: false,
    transparent: true,
  });

  //获取模型
  getModels();

  //随机点
  let random = [];
  for (let i = 0; i < 7600 * 3; i++) {
    random.push((Math.random() - 0.5) * 4);
  }
  pointsVertices = new Float32Array(random);
  let geometry = new THREE.BufferGeometry();
  geometry.setAttribute(
    "position",
    new THREE.BufferAttribute(pointsVertices, 3)
  );
  pointsInit = new THREE.Points(geometry, material);
  scene.add(pointsInit);

  //相机
  threePara.camera = new THREE.PerspectiveCamera(
    45,
    threeBox.clientWidth / threeBox.clientHeight,
    0.1,
    100
  );
  threePara.camera.position.set(0, 0, 2);
  threePara.camera.lookAt(0, 0, 0);

  //渲染器
  threePara.renderer = new THREE.WebGLRenderer();
  threePara.renderer.setPixelRatio(window.devicePixelRatio);
  threePara.renderer.setSize(threeBox.clientWidth, threeBox.clientHeight);
  threeBox.appendChild(threePara.renderer.domElement);

  //让粒子转一会儿
  setTimeout(() => {
    let interval = setInterval(() => {
      if (pointsOne && pointsTwo && pointsThree && pointsFour && pointsFive) {
        clearInterval(interval);
        loadReady = true;
        transformModel(nowModel);
      }
    }, 500);
  }, 3000);
}

onMounted(() => {
  threeBox = container.value.threeBox;
  threePara = container.value.threePara;
  init();
  animate();
});
</script>
